﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Data.Linq;
using System.Text;
using System.Linq.Expressions;
using CoolCode.Data.Linq; 
using CoolCode.Entities;

namespace CoolCode.Services
{
    public abstract class ServiceBase : ITrackService
    {
        protected XDataContext db;

        public virtual bool Log { get; set; }

        #region Data Access Object

        private IRepository<Log> _logger = null;
        public IRepository<Log> Logger
        {
            get
            {
                if (_logger == null)
                    _logger = this.CreateRepository<Log>();
                return _logger;
            }
            set
            {
                _logger = value;
            }
        }

        #endregion

        protected string connectionString;

        public ServiceBase()
            : this(string.Empty)
        {

        }

        public ServiceBase(string connectionString)
        {
            this.connectionString = connectionString;
            this.Log = true;
            this.Refresh();
        }

        public ServiceBase(XDataContext dataContext)
        {
            db = dataContext;
        }

        public virtual void Refresh()
        {
            if (string.IsNullOrEmpty(connectionString))
                db = DataContextFactory.Create();
            else
                db = DataContextFactory.Create(connectionString);
        }

        protected virtual IRepository<T> CreateRepository<T>() where T : class
        {
            return db.Create<T>();
        }

        public virtual void Submit()
        {
            db.SubmitChanges();
        }

        /// <summary>
        /// save program log and submit transation
        /// </summary>
        /// <param name="entity"></param>
        public virtual void LogAndSubmit(Log entity)
        {
            if (this.Log && entity != null)
                Logger.Insert(entity);
            this.Submit();
        }

        private ILoadOption options;

        protected virtual  ILoadOption  LoadWith<T>(Expression<Func<T, object>> property)
        {  
            return (options ?? new LoadOption(db)).LoadWith<T>(property);
        }
         
    }

    public interface ILoadOption
    {
        ILoadOption LoadWith<T>(Expression<Func<T, object>> property);
        void EndLoad();
    }

    public class LoadOption : ILoadOption
    {
        private DataContext db;
        DataLoadOptions opt;
        public LoadOption(DataContext context)
        {
            db = context;
            opt = new DataLoadOptions();
        }

        #region ILoadOption Members

        public ILoadOption LoadWith<T>(Expression<Func<T, object>> property)
        {
            opt.LoadWith<T>(property);
            return this;
        }

        public void EndLoad()
        {
            db.LoadOptions = opt;
        }

        #endregion
    }
}
